package xddq

import (
	"fmt"
	"strings"
	"time"
	D "websocket_apn/define"
	"websocket_apn/log"
	"websocket_apn/proto"
)

var LKAddType = []string{
	"未探索",     //0
	"起始点",     //1
	"未探索",     //2
	"怪物",      //3
	"已探索",     //4
	"阴玉",      //5
	"未探索",     //6
	"无法到达的地方", //7
}

const (
	LKMJ_Data_type_Unexplored = 0 //未探索
	LKMJ_Data_type_Start      = 1 //地图起始点
	LKMJ_Data_type_Monster    = 3 //怪物
	LKMJ_Data_type_Explored   = 4 //已探索
	LKMJ_Data_type_Ying_Yu    = 5 //阴玉
	LKMJ_Data_type_Yang_Yu    = 6 //阳玉
	LKMJ_Data_type_Unreached  = 7 //无法到达的地方
)

/*
EA 07 龙晶银匣
F5 07 龙
F6 07 囚牛
F7 07 寒渊雪龙
前往下一层
[DEBUG] [2024/10/04 11:18:32] [PRJ/websocket_apn/main_test.go]:[  193]:   ↑↑↑↑↑ S_DRAGON_HOME_EXPLORE_GO_NEXT_FLOOR - len:23
[DEBUG] [2024/10/04 11:18:32] [PRJ/websocket_apn/main_test.go]:[  200]:   PayloadBytes: 71 AB 00 00 00 17 00 03 37 87 00 00 02D4 07 01 81 E2 08 B3 E7 E7 04
探索怪物
[DEBUG] [2024/10/04 11:24:10] [PRJ/websocket_apn/main_test.go]:[  193]:   ↑↑↑↑↑ S_DRAGON_HOME_EXPLORE - len:31
[DEBUG] [2024/10/04 11:24:10] [PRJ/websocket_apn/main_test.go]:[  200]:   PayloadBytes: 71 AB 00 00 00 1F 00 03 37 88 00 00 02D4 07 01 81 E2 08 B3 E7 E7 04 12 04 08 02 10 04 18 02

*/

func LongKuMoveData(path []Point) string {
	data := ""
	for _, point := range path {
		data += fmt.Sprintf("12 04 08 %02X 10 %02X ", point.x, point.y)
	}
	return data
}

//查看龙窟秘境信息
func (xd *XdDriver) CheckLongKuMapInfoData(allInfo D.LongKuMapInfo) {
	log.Infof("龙窟秘境-获取地图信息成功")
	if len(allInfo.Gift) > 0 {
		log.Infof("龙窟秘境-领取礼物%#v", allInfo.Gift)
		for _, giftId := range allInfo.Gift {
			xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_RECEIVE_REWARD, fmt.Sprintf("08 %s 10 %02X", xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID, giftId)))
			time.Sleep(3 * time.Second)
		}
		xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_EXPLORE_GO_NEXT_FLOOR, "08"+xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID))
		xd.ResetTaskByID(proto.S_DRAGON_HOME_EXPLORE_DATA)
		return
	}
	if allInfo.YinYu && allInfo.YangYu {
		log.Infof("龙窟秘境-前往下一层")
		xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_EXPLORE_GO_NEXT_FLOOR, "08"+xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID))
		xd.ResetTaskByID(proto.S_DRAGON_HOME_EXPLORE_DATA)
		return
	}
	self := D.LongKuPersonInfo{}
	findSelf := false
	for _, person := range allInfo.Person {
		if person.ID == xd.UserData.UserID || strings.Contains(person.Name, "皮皮华") {
			self = person
			findSelf = true
			xd.UserData.LongKuStrength = person.Strength
		}
	}
	if !findSelf {
		return
	}
	log.Errorf("龙窟秘境-当前所在龙窟%d层 坐标位置(%d,%d) 剩余体力%d 阴玉%t 阳玉%t 下一次体力刷新时间%s", self.Level, self.X, self.Y, self.Strength, allInfo.YinYu, allInfo.YangYu, self.Time.Format("15:04:05"))
	path := LkFindPath(Point{self.X, self.Y}, allInfo.MapData)
	if path == nil {
		log.Errorf("龙窟秘境-寻路失败")
	} else {
		moveData := LongKuMoveData(path[:len(path)-1])
		if len(moveData) > 0 {
			log.Errorf("龙窟秘境-开始移动")
			xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_EXPLORE_MOVE, fmt.Sprintf("08 %s %s",
				xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID, moveData)))
		}
		endP := path[len(path)-1]
		log.Errorf("龙窟秘境-开始探寻坐标(%d,%d)", endP.x, endP.y)
		xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_EXPLORE, fmt.Sprintf("08 %s 12 04 08 %02X 10 %02X 18 00",
			xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID, endP.x, endP.y)))
		xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_EXPLORE, fmt.Sprintf("08 %s 12 04 08 %02X 10 %02X 18 01",
			xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID, endP.x, endP.y)))
	}
	if xd.UserData.LongKuStrength > 0 {
		if xd.UserData.LongKuStrength < 8 && xd.UserData.LongKuGrass > 0 {
			grassNum := xd.UserData.LongKuGrass
			if grassNum > 5 {
				grassNum = 5
			}
			log.Errorf("龙窟秘境-龙须草剩余%d ,开始使用%d根增加%d体力", xd.UserData.LongKuGrass, grassNum, grassNum*2)
			xd.Send(proto.Get_Cmd_Data(xd.userInfo.PlayerId, proto.S_DRAGON_HOME_REPLENISH_STRENGTH, fmt.Sprintf("08 %s 10 %02X",
				xd.UserData.Activity[D.Activity_Dragon_Cave_Secret_Realm].ID, grassNum)))
		}
		xd.ResetTaskByID(proto.S_DRAGON_HOME_EXPLORE_DATA)
	} else {
		xd.ResetTaskByTime(proto.S_DRAGON_HOME_EXPLORE_DATA, self.Time)
	}
}

//查看龙窟秘境体力信息
func (xd *XdDriver) CheckLongKuStrengthInfoData(info D.LongKuStrengthInfo) {
	xd.UserData.LongKuStrength = info.Strength
	if info.Strength > 0 {
		xd.ResetTaskByID(proto.S_DRAGON_HOME_EXPLORE_DATA)
	}
}

type Point struct {
	x, y int
}

var LkDirections = []Point{
	{0, 1},  // right
	{1, 0},  // down
	{0, -1}, // left
	{-1, 0}, // up
}

func LkIsValid(x, y int, mapData [][]byte) bool {
	return x >= 0 && x < len(mapData) && y >= 0 && y < len(mapData[0]) && mapData[x][y] != LKMJ_Data_type_Unreached
}

func LkFindMonsterAround(x, y int, mapData [][]byte) *Point {
	for _, dir := range LkDirections {
		newX, newY := x+dir.x, y+dir.y
		if LkIsValid(newX, newY, mapData) && (mapData[newX][newY] == LKMJ_Data_type_Monster || mapData[newX][newY] == LKMJ_Data_type_Ying_Yu || mapData[newX][newY] == LKMJ_Data_type_Yang_Yu) {
			return &Point{newX, newY} // Found a monster
		}
	}
	return nil // No monster found
}

func LkFindExploreAround(x, y int, mapData [][]byte) *Point {
	for _, dir := range LkDirections {
		newX, newY := x+dir.x, y+dir.y
		if LkIsValid(newX, newY, mapData) && mapData[newX][newY] == LKMJ_Data_type_Unexplored {
			return &Point{newX, newY} // Found a monster
		}
	}
	return nil // No monster found
}

func LkSearchAdjacentPoints(mapData [][]byte) []Point {
	var validPoints []Point
	for x := 0; x < len(mapData); x++ { // 遍历行
		for y := 0; y < len(mapData[x]); y++ { // 遍历列
			if LkIsValid(x, y, mapData) && (mapData[x][y] == LKMJ_Data_type_Start || mapData[x][y] == LKMJ_Data_type_Explored) {
				validPoints = append(validPoints, Point{x, y})
			}
		}
	}
	return validPoints
}

func LkFindMonsterInArea(mapData [][]byte) (endP, targetP *Point) {
	adjacentPoints := LkSearchAdjacentPoints(mapData)
	for _, point := range adjacentPoints {
		targetP = LkFindMonsterAround(point.x, point.y, mapData)
		if targetP != nil {
			return &point, targetP // Found a monster in the adjacent area
		}
	}
	return nil, nil // No monster found in adjacent areas
}

func LkExploreRandomly(mapData [][]byte) (endP, targetP *Point) {
	adjacentPoints := LkSearchAdjacentPoints(mapData)
	for _, point := range adjacentPoints {
		targetP := LkFindExploreAround(point.x, point.y, mapData)
		if targetP != nil {
			return &point, targetP // Found a monster in the adjacent area
		}
	}
	return nil, nil // No unexplored area found
}
func LkCalcPath(startP, endP, targetP *Point, mapData [][]byte) []Point {
	// 定义一个队列用于BFS
	queue := []Point{*startP}
	// 创建一个访问记录的二维切片
	visited := make([][]bool, len(mapData))
	for i := range visited {
		visited[i] = make([]bool, len(mapData[i]))
	}
	// 记录每个点的前驱点用于路径回溯
	prev := make(map[Point]*Point)

	// 将起始点标记为已访问
	visited[startP.x][startP.y] = true

	// BFS循环
	for len(queue) > 0 {
		current := queue[0]
		queue = queue[1:]
		// 如果到达终点，构建路径
		if current.x == endP.x && current.y == endP.y {
			var path []Point
			for p := &current; p != nil; p = prev[*p] {
				path = append([]Point{*p}, path...)
			}
			path = append(path, *targetP)
			path = path[1:]
			return path
		}
		// 遍历四个方向
		for _, dir := range LkDirections {
			newX, newY := current.x+dir.x, current.y+dir.y
			if LkIsValid(newX, newY, mapData) && !visited[newX][newY] && (mapData[newX][newY] == LKMJ_Data_type_Explored || mapData[newX][newY] == LKMJ_Data_type_Start) {
				// 标记新点已访问
				visited[newX][newY] = true
				queue = append(queue, Point{newX, newY})
				prev[Point{newX, newY}] = &current // 记录前驱点
			}
		}
	}
	// 如果没有找到路径
	return nil
}

func LkFindPath(startP Point, mapData [][]byte) []Point {
	endP := &Point{}
	targetP := &Point{}
	// Then check adjacent points
	endP, targetP = LkFindMonsterInArea(mapData)
	if endP == nil {
		endP, targetP = LkExploreRandomly(mapData)
	}
	if endP == nil {
		return nil
	}
	return LkCalcPath(&startP, endP, targetP, mapData)
}
